'''
Created on Oct 3, 2012

@author: Himanshu
'''
import csv
import numpy as np
import matplotlib.pyplot as plt
import sys
import cPickle as pickle
import os
from featureset import gesture

class Parsers:
    '''
    parses the .csv data files. Also contains methods to build training set out of parsed data. 
    For now only collects Acceleration Sensor data. 
    '''

    def __init__(self):
        """
        contructor
        """
        self.seconds = []
        self.eventTimeStamps = []
        self.aX = []
        self.aY = []
        self.aZ = []
        self.gX = []
        self.gY = []
        self.gZ = []
        self.endAdjust = 0
        self.startDelay = 5
        
    def parse(self, fileName):
        """
        main parser function. Returns event timestamps, x, y, and z acceleration vectors after initial delay and before final 
        pause. Stores the parsed data in class features as lists.
        """
        currentPath = os.getcwd();
        with open(currentPath+"/phidgetData//" + fileName + '.csv', 'r') as csvfile:
                reader = csv.reader(csvfile, dialect = 'excel')
                for row in reader:
                    if ((row[0] != '') and (row.__len__() == 8)):
                        offset = int(row[0])
                        self.seconds.append(offset)
                        eventTimeStamp = offset*1000 + int(row[1])/1000
                        self.eventTimeStamps.append(eventTimeStamp)       
                        self.aX.append(float(row[2]))
                        self.aY.append(float(row[3])) 
                        self.aZ.append(float(row[4])) 
                        self.gX.append(float(row[5]))
                        self.gY.append(float(row[6])) 
                        self.gZ.append(float(row[7]))              
    
        
    
    def getFeatures(self, mode, noGestures, gestureInterval, windowSize, t , gestureLength):
        """
        Builds feature vectors according to mode (desired features) and the startTime. This collects feature vectors
        for multiple instances for one gesture. For example, the 'phone slap' gesture performed noGestures times 
        with gestureInterval seconds between each gesture. All the possible feature vectors extracted will be returned
        """
        
        "Check for empty class features"
        if (self.eventTimeStamps.__len__() == 0):
            print "Empty TimeStamps. Run parse script first!"
            return
        
        endTime = self.seconds[0] + noGestures*gestureInterval - self.endAdjust
        
        #attempt to find end time
        try:
            endIndex = self.seconds.index(endTime + 1)
        except ValueError:
            print "Range not in data set"
            return
        return self.windowMeanAnalyzer(mode , windowSize, self.startDelay, endIndex, t , gestureLength)
        """Notice this does not take in noGestures. It identifies on its own how many gestures it can find in the 
        time interval"""
        

    def windowMeanAnalyzer(self , mode , windowSize, gstartIndex , gendIndex , t , gestureLength):
        """
        method to automatically identify number of gesture instances and gesture feature vectors based on different modes.
        startIndex and endIndex are derived from getFeatures method. Current supported mode is 'acceleration_norm'.
        """
        " create splices between begin and end time "
        rawFeatures = [self.aX[gstartIndex:gendIndex+1] , self.aY[gstartIndex:gendIndex+1] , self.aZ[gstartIndex:gendIndex+1]]
        rawaX = self.aX[gstartIndex:gendIndex+1]
        rawaY = self.aY[gstartIndex:gendIndex+1]
        rawaZ = self.aZ[gstartIndex:gendIndex+1]
        rawgX = self.gX[gstartIndex:gendIndex+1]
        rawgY = self.gY[gstartIndex:gendIndex+1]
        rawgZ = self.gZ[gstartIndex:gendIndex+1]
        eventTime = self.eventTimeStamps[gstartIndex:gendIndex+1]
        
        if (mode == 'acceleration_norm'):
            aRaw = np.sum(np.abs(np.transpose(rawFeatures))**2,axis = -1)**(1./2) #net acceleration
            plt.figure()
            plt.plot(eventTime,aRaw)
            plt.hold(True)
            
            " subtract out acceleration mean and calculate window means "
            globalMean = np.mean(aRaw)
            a = np.subtract(aRaw,globalMean)
            a = np.abs(a)
            windowMeans = []
            windowStds = []
            for i in range(0 , gendIndex - gstartIndex + 2 - windowSize):
                localMean = np.mean(a[i:i+windowSize])
                windowMeans.append(localMean)
                localStd = np.std(a[i:i+windowSize])
                windowStds.append(localStd)
            for i in range(0,((windowSize-1)/2)):
                windowMeans.insert(0,0)
                windowMeans.append(0)
            plt.plot(eventTime,windowMeans)
            
            " extract interest points based on smoothed window means going over a threshold "
            i = ((windowSize-1)/2)
            interestPoints = []
            interestTimings = []
            #thresh = 0.5*globalStd
            thresh = np.mean(windowStds) + t*np.std(windowStds)
            while( i < (windowMeans.__len__() - ((windowSize-1)/2) + 1)):
                if (windowMeans[i] > thresh):
                    " create 5 index cushion before gesture start if possible "
                    if ((i - 5) > 0):
                        startTime = eventTime[i-5] 
                        startIndex = i - 5
                    else: 
                        startTime = eventTime[i]
                        startIndex = i 
                        
                    " guess gesture end time by gestureLength"
                    guessEndTime = startTime + gestureLength*(10**3)
                    while ((i<eventTime.__len__()) and (eventTime[i]<guessEndTime)):
                        i += 1
                    " however, keep recording till smooth mean drops below threshold"
                    while ((i<windowMeans.__len__()) and (windowMeans[i] > thresh)):
                        i += 1
                    " if possible, create a 5 index cushion after end of gesture"
                    if ((i +5 ) < windowMeans.__len__()):
                        i += 5
                    else:
                        count = 0
                        while ((count < 5) and (i < windowMeans.__len__())):
                            i += 1
                            count += 1
                    endIndex = i
                    if (endIndex == eventTime.__len__()):
                        endIndex -=1
                        
                    "record the start and end of the gesture as an interest point"
                    interestPoints.append((startIndex,endIndex))
                    interestTimings.append((startTime,eventTime[endIndex]))
                i += 1
            print "Index harvested: " , interestPoints
            print "Event Time harvested: " , interestTimings
            for point in interestTimings:
                plt.axvline(x = point[0] , color = 'r')
                plt.axvline(x = point[1] , color = 'g')
            
            "Harvest features"
            aNormf = []
            aXf = []
            aYf = []
            aZf = []
            gXf = []
            gYf = []
            gZf = []
            
            times = []
            for point in interestPoints:
                aNormf.append(aRaw[point[0]:point[1]])
                aXf.append(rawaX[point[0]:point[1]])
                aYf.append(rawaY[point[0]:point[1]])
                aZf.append(rawaZ[point[0]:point[1]])
                gXf.append(rawgX[point[0]:point[1]])
                gYf.append(rawgY[point[0]:point[1]])
                gZf.append(rawgZ[point[0]:point[1]])
                times.append(eventTime[point[0]:point[1]])
            print "Total number of feature vectors harvested: " , interestPoints.__len__() , "."
            plt.show()
            return (aNormf , aXf , aYf , aZf , gXf , gYf , gZf , times) 
        else:
            print "Invalid mode. Allowed modes: acceleration_norm'"
            return
        
    def buildPickles(self , gestureName , noGestures , gestureInterval):
        """The feature collector is highly customizable. The def is as follows:
        def getFeatures(mode, noGestures, gestureInterval, windowSize, smoothSize, sigma, t)
        windowSize is for computing means
        smoothSize, sigma are for smoothing means (value of 0 means no smoothing)
        t is related to threshold on smoothed means for qualifying as gesture"""  
        
        mode = 'acceleration_norm'
        
        windowSize = 5
        t = 1
        gestureLength = 5
        
        while(True):
            #def getFeatures(mode, noGestures, gestureInterval, windowSize, smoothSize, sigma, t)
            features = self.getFeatures(mode, noGestures , gestureInterval , windowSize , t , gestureLength)
            if (features != None and features[0].__len__() <= 10):
                response = raw_input('Please enter y if satisfied an n if not\n')
                if (response == 'y'):
                    pickleName = gestureName + '.pkl'
                    output = open(os.getcwd()+'\pickles\\'+pickleName, 'wb')
                    pickle.dump(gestureName , output)
                    pickle.dump(features[0].__len__() , output)
                    gest = gesture(gestureName[:-1] , features)
                    pickle.dump(gest,output)
                    print 'Pickle written, name = ', pickleName
                    break
                else:
                    print "Last entered values: Window Size = ", windowSize
                    print "Threshold =  ", t , "\nEnd Adjustement = " , self.endAdjust , "\nMinimum Gesture Length: " , gestureLength
                    print "Start Delay = " , self.startDelay
                    windowSize = int(raw_input('Please enter averaging window Size: \n'))
                    t = float(raw_input('Please enter threshold: \n'))
                    self.endAdjust = int(raw_input('Please enter end adjustment: \n'))
                    self.startDelay = int(raw_input('Please enter start delay: \n'))
                    gestureLength = int(raw_input('Please enter Minimum Gesture Length: \n'))
                    
            else:
                print "Too many features. Must be less than 10 \n"
                print "Last entered values: Window Size = ", windowSize
                print  "\nThreshold =  ", t , "\nEnd Adjustement = " , self.endAdjust , "\nMinimum Gesture Length: " , gestureLength
                print "Start Delay = " , self.startDelay
                windowSize = int(raw_input('Please enter averaging window Size: \n'))
                t = float(raw_input('Please enter threshold: \n'))
                self.endAdjust = int(raw_input('Please enter end adjustment: \n'))
                self.startDelay = int(raw_input('Please enter start delay: \n'))
                gestureLength = int(raw_input('Please enter Minimum Gesture Length: \n'))
                
            
        
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
                